package com.flashflexpro.tanksinbattle.battlescene {
import com.flashflexpro.tanksinbattle.battlescene.dto.BattleSceneDto;

import com.flashflexpro.tanksinbattle.battlescene.dto.BattleSceneObjectDto;
import com.flashflexpro.tanksinbattle.battlescene.dto.XyVO;
import com.flashflexpro.tanksinbattle.loader.LoadModuleEvent;
import com.flashflexpro.tanksinbattle.scene.dto.Dto;

import com.flashflexpro.tanksinbattle.scene.dto.ModuleDto;

import flash.display.BitmapData;
import flash.display.DisplayObjectContainer;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.filters.GlowFilter;
import flash.geom.Point;
import flash.system.ApplicationDomain;

public class BattleSceneBase extends MovieClip {


    private var _sceneDto:BattleSceneDto;

    public function BattleSceneBase(sceneDto:BattleSceneDto) {
        _sceneDto = sceneDto;
        initScene();
        addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    }

    private function initScene():void {

        //4 layers
        for (var howManyLayers:int = 0; howManyLayers < 4; howManyLayers  ++) {
            addChild(new Sprite());
        }

        if (_sceneDto.walls == null || _sceneDto.walls.length == 0) {
            trace("using default wall");
            if (defaultWall == null) {
                throw new Error("Defaultwall not founded!!");
            }
            var wdto:BattleSceneObjectDto = new BattleSceneObjectDto();
            wdto.initialPosition = new XyVO();
            var wall:BattleSceneObject = new BattleSceneObject(wdto, BattleScene(this));
            wall.addChild(defaultWall);

            hittableLayer.addChildAt(wall, 0);
            hitted.push(wall);
        }
        else {
            addModuleArray(_sceneDto.walls, hittableLayer)
        }

        addModuleArray(_sceneDto.forts, hittableLayer);
        addModuleArray(_sceneDto.doors, hittableLayer);
        addModuleArray(_sceneDto.tanks, hittableLayer);


        if (_sceneDto.background == null) {
            trace("background not found ");
        }
        else {
            addModule(_sceneDto.background, background, 0);
        }


        if (_sceneDto.foreground == null) {
            trace("foregroud not found ");
        }
        else {
            addModule(_sceneDto.foreground, foreground, 2);
        }

    }

    public var defaultWall:MovieClip;

    private function addModuleArray(ms:Array, p:DisplayObjectContainer):void {
        for each(var m:ModuleDto in ms) {
            addModule(m, p);
        }
    }

    private function addModule(m:ModuleDto, p:DisplayObjectContainer, index:int = -1):void {
        var c:Class = ApplicationDomain.currentDomain.getDefinition(m.dependency.entryClass) as Class;
        if (index >= 0 || m is BattleSceneObjectDto) {
            if (index >= 0) {
                p.addChildAt(new c(m, this), index);
            }
            else {
                p.addChildAt(new c(m, this), ( m as BattleSceneObjectDto ).zPosition);
            }
        } else {
            p.addChild(new c(m, this));
        }
    }


    private var _from:Dto;

    public function get fromDto():Dto {
        return _from;
    }

    public function start(from:Dto):void {
        _from = from;

        dispatchEvent(new LoadModuleEvent(LoadModuleEvent.MODULE_READY));
    }

    public function get background():DisplayObjectContainer {
        return getChildAt(0) as DisplayObjectContainer;
    }

    public function get hittableLayer():DisplayObjectContainer {
        return getChildAt(1) as DisplayObjectContainer;
    }

    public function get foreground():DisplayObjectContainer {
        return getChildAt(2) as DisplayObjectContainer;
    }

    public function get dialogLayer():DisplayObjectContainer {
        return getChildAt(3) as DisplayObjectContainer;
    }


    protected function onAddedToStage(event:Event):void {


        addEventListener(Event.ENTER_FRAME, onEnterFrame);
        addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    }

    protected function onRemovedFromStage(event:Event):void {
        removeEventListener(Event.ENTER_FRAME, onEnterFrame);
        removeEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage);
    }


    private var _hitting:Array = [];
    private var _hitted:Array = [];


    public function get hitting():Array {
        return _hitting;
    }

    public function get hitted():Array {
        return _hitted;
    }


    protected function onEnterFrame(event:Event):void {
    }

    protected function updateEach(time:int):void {
        var n:int = hittableLayer.numChildren;
        for (var i:int = 0; i < n; i ++) {
            ( hittableLayer.getChildAt(i) as BattleSceneObject ).update(time);
        }
    }

    protected function checkHit():void {
        var ingNum:int = hitting.length;
        var edNum:int = hitted.length;

        for (var i:int = 0; i < ingNum; i ++) {
            var ing:BattleSceneObject = hitting[ i ];
            var ingBit:BitmapData;
            for (var j:int = 0; j < edNum; j ++) {
                var ed:BattleSceneObject = hitted[ j ];
                //todo: optimize this, there're  so many conditions that don't need to check
                if (ing != ed && ing.hitTestObject(ed) ){
                    if( ingBit == null ){
                        ingBit = ing.getHitBitMap();
                    }
                    var edBit:BitmapData = ed.getHitBitMap();
                    if( ingBit.hitTest(new Point(ing.x, ing.y), 255, edBit, new Point(ed.x, ed.y), 255)){
                        ing.hit = ed;
                        ed.hit = ing;
                        ing.filters = [ new GlowFilter()];
                        ed.filters = [ new GlowFilter()];
                    }
                    else{
                        ing.filters = null;
                        ed.filters = null;
                    }
                }
                else{
                    ing.filters = null;
                    ed.filters = null;
                }
            }
        }
    }


public function destroy():void {
    removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
    removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
}
}